package com.easyaop.test.core.demo.annotation;

import com.easyaop.test.core.annotation.Aop;
import com.easyaop.test.core.entity2.Bean3;
import com.easyaop.test.core.entity.User;
import com.easyaop.test.core.entity.Bean;
import com.easyaop.test.core.intercept.VirtualMethodAdvice;
import com.easyaop.test.core.listener.DebugAgentListener;

import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;

import java.io.File;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;

/**
 * @author lipan
 * @since 2025-01-20
 */
public class AnnotationTest2 {
    private static final String ROOT_PATH = "D:/project/workspace/aop";

    public static void main(String[] args) throws UnmodifiableClassException {
        Instrumentation install = ByteBuddyAgent.install();
        Bean bean2 = new Bean();

        // AnnotationPointcut pointcut = new AnnotationPointcut(Bean.class);
        // System.out.println(Bean.class.getName());
        new AgentBuilder.Default()
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) // 启用重定义策略
                .disableClassFormatChanges()
                .type(ElementMatchers.nameStartsWith("com.easyaop.test.core.entity").and(ElementMatchers
                        .isAnnotatedWith(Aop.class)))
                .transform((builder, typeDescription, classLoader, javaModule, protectionDomain) -> {
                    ElementMatcher<MethodDescription> matcher =
                            ElementMatchers.any().and(ElementMatchers.not(ElementMatchers.isConstructor()));
                    builder.method(matcher);
                    return builder.visit(Advice.to(VirtualMethodAdvice.class).on(matcher));
                })
                .type(ElementMatchers.nameStartsWith("com.easyaop.test.core.entity"))
                .transform((builder, typeDescription, classLoader, javaModule, protectionDomain) -> {
                    ElementMatcher<MethodDescription> matcher = ElementMatchers.isAnnotatedWith(Aop.class);
                    builder.method(matcher);
                    return builder.visit(Advice.to(VirtualMethodAdvice.class).on(matcher));
                })
                .with(new DebugAgentListener())
                .installOn(install);

        Bean bean = new Bean3();
        bean.setId(1L);
        bean.setName("lp");

        User user = new User();
        user.setName("cat");

        System.out.println(user);

        final String beanName = bean.getName();
        System.out.println(beanName);
    }

    private static AgentBuilder.Listener getListener() {
        return new DebugAgentListener();
    }

    static {
        String path = ROOT_PATH + File.separator + "DUMP_CLASS";
        System.setProperty(DebugAgentListener.DEBUG_LOCATION_PROPERTY, path);
    }
}
